#include <stdio.h>
#include <string.h>
#if defined(TEST_TARGET_txls)
#include <varch/command.h>
#include <varch/unitt.h>
#include <varch/txls.h>
#else  
#include "init.h"
#include "command.h"
#include "unitt.h"
#include "kern.h"
#include "txls.h"
#endif

/************************************************************************************/
/************************************* Unit Test ************************************/
/************************************************************************************/

// #define EXIT_TEST
extern uint64_t unitt_clock(void);

static int test_0(void)
{
    for (int i = 0; i < 100; i++)
    {
        if (0) 
        {
            
            #if defined (EXIT_TEST)
            exit(0);
            #endif 
            return UNITT_E_FAIL;
        }
    }
    
    return UNITT_E_OK;
}

static void unitt_task(void)
{
    static UNITT_TCASE rand_tests[] = {
        UNITT_TCASE(test_0),
        // UNITT_TCASE(test_1),
        // UNITT_TCASE(test_2),
    };

    static UNITT suites[] = {
        { "xxx suite", rand_tests, sizeof(rand_tests) / sizeof(rand_tests[0]) , unitt_clock },
    };

    UNITT_EXE(suites);
}

/************************************************************************************/
/************************************* Base Test ************************************/
/************************************************************************************/

#define READ_FILE "test/file/read.md"
#define WRITE_FILE "test/file/write.md"

static void txls_preview(txls_t txls)
{
    char* s;
    int len = 0;
    if (!txls) return;
    s = txls_dumps(txls, 1, &len);
    printf("s %p\r\n", s);
    if (!s) return;
    printf("len = %d, <%d, %d>\r\n%s\r\n", len, txls_col(txls), txls_row(txls), s);
    free(s);
}

static void test_create(void)
{
    txls_t txls = NULL;
    txls = txls_create(3, 5);
    if (txls)
    {
        printf("txls_create success!!! %p\r\n", txls);
    }
    txls_delete(txls);
}

static void test_ranks(void)
{
    txls_t txls = NULL;

    txls = txls_create(3, 5);

    printf("txls_row %d\r\n", txls_row(txls));
    printf("txls_col %d\r\n", txls_col(txls));

    txls_delete(txls);
}

static void test_set(void)
{
    txls_t txls = NULL;
    unsigned int row = 0, col = 0;
    const char *array[3][5] = {
        {"ID",          "Name",     "Gender",   "Age",  "Height"},
        {"20240107001", "ZhangSan", "Man",      "18",   "178"},
        {"20240107002", "LiSi",     "Woman",    "24",   "162"},
    };

    txls = txls_create(3, 5);

    row = txls_row(txls);
    col = txls_col(txls);
    printf("row %u\r\n", row);
    printf("col %u\r\n", col);

    for (int c = 1; c <= col; c++)
    {
        txls_set_head(txls, c, array[0][c]);
    }
    for (int r = 1; r <= row; r++)
    {
        for (int c = 1; c <= col; c++)
        {
            txls_set_text(txls, r - 1, c, array[r - 1][c - 1]);
        }
    }

    txls_preview(txls);

    printf("txls[1][2] %s\r\n", txls_get_text(txls, 1, 2));

    txls_delete(txls);
}

static void test_op_ranks(void)
{
    txls_t txls = NULL;
    unsigned int row = 0, col = 0;
    char *text = NULL;
    const char *array[3][5] = {
        {"ID",          "Name",     "Gender",   "Age",  "Height"},
        {"20240107001", "ZhangSan", "Man",      "18",   "178"},
        {"20240107002", "LiSi",     "Woman",    "24",   "162"},
    };

    for (int i = 0; i < 5; i++)
    {
        printf("-------------------------------------\r\n");
        txls = txls_create(3, 5);
        row = txls_row(txls);
        col = txls_col(txls);
        for (int c = 1; c <= col; c++)
        {
            txls_set_head(txls, c, array[0][c]);
        }
        for (int r = 1; r <= row; r++)
        {
            for (int c = 1; c <= col; c++)
            {
                txls_set_text(txls, r - 1, c, array[r - 1][c - 1]);
            }
        }

        switch (i)
        {
        case 0:
        {
            printf("Before OP:\r\n");
        } break;
        case 1:
        {
            printf("txls_insert_row:\r\n");
            txls_insert_row(txls, 2);
        } break;
        case 2:
        {
            printf("txls_insert_col:\r\n");
            txls_insert_col(txls, 2);
        } break;
        case 3:
        {
            printf("txls_delete_row:\r\n");
            txls_delete_row(txls, 2);
        } break;
        case 4:
        {
            printf("txls_delete_col:\r\n");
            txls_delete_col(txls, 2);
        } break;
        default:
            break;
        }

        txls_preview(txls);
        txls_delete(txls);
    }
}

static void test_align(void)
{
    txls_t txls = NULL;
    unsigned int row = 0, col = 0;
    const char *array[3][5] = {
        {"ID",          "Name",     "Gender",   "Age",  "Height"},
        {"20240107001", "ZhangSan", "Man",      "18",   "178"},
        {"20240107002", "LiSi",     "Woman",    "24",   "162"},
    };

    txls = txls_create(3, 5);

    row = txls_row(txls);
    col = txls_col(txls);

    for (int c = 1; c <= col; c++)
    {
        txls_set_head(txls, c, array[0][c]);
    }
    for (int r = 1; r <= row; r++)
    {
        for (int c = 1; c <= col; c++)
        {
            txls_set_text(txls, r - 1, c, array[r - 1][c - 1]);
        }
    }

    txls_set_align(txls, 1, TXLS_ALIGN_UNKNOW);
    txls_set_align(txls, 2, TXLS_ALIGN_LEFT);
    txls_set_align(txls, 3, TXLS_ALIGN_RIGHT);
    txls_set_align(txls, 4, TXLS_ALIGN_CENTER);
    txls_preview(txls);

    txls_delete(txls);
}

static void test_load(void)
{
    txls_t x = NULL;  // Define the txls object, initialized to NULL as usual

    /* Load the txls file */
    x = txls_file_load(READ_FILE);
    if (!x) // Loading failed, locating error
    {
        int line, type;
        type = txls_error_info(&line);
        printf("txls parse error! line %d, error %d.\r\n", line, type);
        return;
    }

    /* Iterate over the header to locate the column*/
    int col = 0;
    for (col = 1; col <= txls_col(x); col++)
    {
        if (strcmp("Li Si", txls_get_head(x, col)) == 0)
        {
            break;
        }
    }
    if (col > txls_col(x)) // Not found
    {
        printf("Lookup failed\r\n");
        return;
    }

    /* print info */
    printf("name: %s, age=%s, gender: %s, height=%s, weight=%s, email:%s\r\n", 
    txls_get_text(x, col, 0),
    txls_get_text(x, col, 1),
    txls_get_text(x, col, 2),
    txls_get_text(x, col, 3),
    txls_get_text(x, col, 4),
    txls_get_text(x, col, 5));

    txls_delete(x);
}

static void test_dump(void)
{
    txls_t x = NULL;  // Define the txls object, initialized to NULL as usual

    x = txls_create(4, 5); // Create a 4x5 txls
    if (!x)
    {
        return;
    }

    /* Sets the header of the table, leaving the first column blank */
    txls_set_head(x, 2, "Zhang San");
    txls_set_head(x, 3, "Li Si");
    txls_set_head(x, 4, "Wang Wu");

    /* Set the alignment */
    txls_set_align(x, 2, TXLS_ALIGN_LEFT);
    txls_set_align(x, 3, TXLS_ALIGN_CENTER);
    txls_set_align(x, 4, TXLS_ALIGN_RIGHT);

    /* The first column serves as the information category */
    txls_set_text(x, 1, 1, "age");
    txls_set_text(x, 1, 2, "gender");
    txls_set_text(x, 1, 3, "height");
    txls_set_text(x, 1, 4, "weight");
    txls_set_text(x, 1, 5, "email");

    /* Write per-person information */
    // Zhang San
    txls_set_text(x, 2, 1, "18");
    txls_set_text(x, 2, 2, "man");
    txls_set_text(x, 2, 3, "178.5");
    txls_set_text(x, 2, 4, "65");
    txls_set_text(x, 2, 5, "123321@qq.com");
    // Li Si
    txls_set_text(x, 3, 1, "24");
    txls_set_text(x, 3, 2, "woman");
    txls_set_text(x, 3, 3, "165");
    txls_set_text(x, 3, 4, "48");
    txls_set_text(x, 3, 5, "lisi@163.com");
    // Wang Wu
    txls_set_text(x, 4, 1, "20");
    txls_set_text(x, 4, 2, "man");
    txls_set_text(x, 4, 3, "175");
    txls_set_text(x, 4, 4, "75");
    txls_set_text(x, 4, 5, "ww1234567890@qq.com");

    txls_file_dump(x, WRITE_FILE);

    txls_delete(x);
}

static void test_base(void)
{
    test_load();
    // test_dump();
}

/************************************************************************************/
/*************************************  Command  ************************************/
/************************************************************************************/

static void usage(void)
{
    printf(
"Usage: txls [opt] [arg] ...\n"
"\n"
"options:\n"
"    -e <execute>        Specifies the function to execute, the default is the <base> test\n"
"                        <base>      Test base function\n"
"                        <ut>        Unit test\n"
"                        <create>    Test create and delete functions\n"
"                        <ranks>     Test get ranks infomation functions\n"
"                        <set>       Test set and get functions\n"
"                        <opranks>   Test operate rows and cols functions\n"
"                        <align>     Test set align functions\n"
"                        <dump>      Test dump functions\n"
"                        <load>      Test load functions\n"
"    -h                  Print help\n"
"    -v                  Print version\n"
"    -u [<period>]       Unit test period, unit ms, the default is 1000ms\n"
"\n"

    );
}

static int test(int argc, char *argv[])
{
    char *execute = NULL;
    int ut_period = 1000;

    /* reset getopt */
    command_opt_init();

    while (1)
    {
        int opt = command_getopt(argc, argv, "e:hvu::");
        if (opt == -1) break;

        switch (opt) 
        {
        case 'u' :
            if (command_optarg) ut_period = atoi(command_optarg);
            break;
        case 'e' :
            execute = command_optarg;
            break;
        case 'v' :
            printf("txls version %d.%d.%d\r\n", TXLS_V_MAJOR, TXLS_V_MINOR, TXLS_V_PATCH);
            return 0;
        case '?':
            printf("Unknown option `%c`\r\n", command_optopt);
            return -1;
        case 'h' : 
        default:
            usage();
            return 0;
        }
    }

    if (execute)
    {
        if (!strcmp(execute, "base"))
        {
            test_base();
        }
        else if (!strcmp(execute, "ut"))
        {
            #if defined(TEST_TARGET_txls)
            while (1)
            {
                unitt_task();
                usleep(1000 * ut_period);
            }
            #else  
            printf("create task %d\r\n", task_create(ut_period, unitt_task));
            #endif
        }
        else if (!strcmp(execute, "create"))
        {
            test_create();
        }
        else if (!strcmp(execute, "ranks"))
        {
            test_ranks();
        }
        else if (!strcmp(execute, "set"))
        {
            test_set();
        }
        else if (!strcmp(execute, "opranks"))
        {
            test_op_ranks();
        }
        else if (!strcmp(execute, "align"))
        {
            test_align();
        }
        else if (!strcmp(execute, "dump"))
        {
            test_dump();
        }
        else if (!strcmp(execute, "load"))
        {
            test_load();
        }
    }
    else  
    {
        test_base();
    }
    
    return 0;
}

/************************************************************************************/
/************************************ Test entry ************************************/
/************************************************************************************/

#if defined(TEST_TARGET_txls)
int main(int argc, char *argv[])
{
    return test(argc, argv);
}
#else 
void test_txls(void)
{
    command_export("txls", test);
}
init_export_app(test_txls);
#endif 
